package cn.ibizlab.util.adapter.aspect;

import cn.hutool.core.util.ReflectUtil;
import cn.ibizlab.util.adapter.service.SysRuntimeAdapterService;
import cn.ibizlab.util.adapter.service.SysRuntimeModelService;
import cn.ibizlab.util.adapter.service.impl.DefaultAdapterDataEntityRuntimeBase;
import cn.ibizlab.util.adapter.util.helper.CachedBeanCopier;
import cn.ibizlab.util.adapter.util.constant.DELogicConstant;
import cn.ibizlab.util.adapter.util.helper.DataEntityUtil;
import cn.ibizlab.util.domain.IEntity;
import cn.ibizlab.util.filter.ISearchContext;
import cn.ibizlab.util.helper.BeanCache;
import net.ibizsys.central.cloud.core.dataentity.IDataEntityRuntime;
import net.ibizsys.central.util.IEntityDTO;
import net.ibizsys.model.dataentity.action.IPSDEAction;
import net.ibizsys.runtime.dataentity.action.DEActionTypes;
import net.ibizsys.runtime.util.Entity;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.ibizlab.util.adapter.util.constant.DELogicConstant.*;

/**
 * 处理逻辑处理切面类：用于执行实体处理逻辑、实体行为前/后附加逻辑
 */
@Component
public class SysRuntimeAdapterAspect implements MethodInterceptor {

    @Autowired
    SysRuntimeAdapterService sysRuntimeAdapterService;
    @Autowired
    SysRuntimeModelService sysRuntimeModelService;
    @Autowired
    DataEntityUtil dataEntityUtil;

    /**
     * 执行runtime逻辑
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        if (!(invocation instanceof ProxyMethodInvocation))
            return invocation.proceed();

        ProceedingJoinPoint point = new MethodInvocationProceedingJoinPoint((ProxyMethodInvocation) invocation);

        Object target = point.getTarget();
        String method = point.getSignature().getName();
        Object[] args = point.getArgs();

        boolean enable = enableMethod(target, method, args);
        if (enable) {
            IEntity entity = getEntity(target, method, args);
            DefaultAdapterDataEntityRuntimeBase dataEntityRuntime = (DefaultAdapterDataEntityRuntimeBase) sysRuntimeModelService.getDataEntityRuntime(entity.getClass(), false);
            IPSDEAction ipsdeAction = sysRuntimeModelService.getPSDEAction(dataEntityRuntime, method, false);
            //entity -> entityDto
            Object[] entityDto = createEntityDto(dataEntityRuntime,args);
            //执行实体行为
            Object result = sysRuntimeAdapterService.executeAction(dataEntityRuntime, ipsdeAction, entityDto, !isCustomAction(dataEntityRuntime,ipsdeAction)? point : null);
            //entityDto -> entity (runtime在执行行为逻辑时，会修改args中属性值，需将arg中的参数copy至entity中)
            if (!ObjectUtils.isEmpty(entityDto) && entityDto[0] instanceof IEntityDTO) {
                CachedBeanCopier.copyEntityDto2Entity((IEntityDTO) entityDto[0], entity);
            }
            if(result != null && result instanceof Entity){
                CachedBeanCopier.copyEntityDto2Entity((Entity)result, entity);
            }
            //处理逻辑配置返回值
            if(result != null && result instanceof IEntityDTO){
                CachedBeanCopier.copyEntityDto2Entity((IEntityDTO) result, entity);
            }
            return result != null && !(result instanceof IEntityDTO) && !(result instanceof IEntity) && !(result instanceof Entity)? result : entity;
        }

        //额外参数处理，取消前端传入的联合主键
        processArgs(args);
        return point.proceed();
    }

    /**
     * 创建 entityDto
     * @param args
     * @return
     */
    protected Object[] createEntityDto(IDataEntityRuntime dataEntityRuntime, Object[] args) {
        if(ObjectUtils.isEmpty(args))
            return null;

        List list = new ArrayList();
        for(Object arg : args){
            if(arg instanceof IEntity){
                IEntityDTO entityDto = dataEntityRuntime.createEntity();
                CachedBeanCopier.copyEntity2Dto((IEntity) arg,entityDto);
                //置空前端联合主键
                for(Map.Entry<String,Object> field: entityDto.any().entrySet()){
                    if(!ObjectUtils.isEmpty(field.getValue()) && field.getValue().toString().startsWith("__empty__"))
                        entityDto.set(field.getKey(),null);
                }
                //entityDto中设置原始entity对象
                entityDto.set(DELogicConstant.PARAM_DATAENTITY,arg);
                list.add(entityDto);
            }
        }
        return list.toArray();
    }

    /**
     * 从参数列表中获取实体
     * @param args
     * @return
     */
    protected IEntity getEntity(Object[] args) {
        if (ObjectUtils.isEmpty(args))
            return null;

        for (Object arg : args) {
            if (arg instanceof IEntity) {
                return (IEntity) arg;
            } else if (arg instanceof List) {
                for (Object obj : (List) arg) {
                    IEntity entity = getEntity(new Object[]{obj});
                    if (entity != null)
                        return entity;
                }
            }else if(arg instanceof ISearchContext){
                return null;
            }
        }
        return null;
    }

    /**
     * 获取实体
     * @param service
     * @param method
     * @param args
     * @return
     */
    protected IEntity getEntity(Object service, String method, Object[] args) {
        IEntity entity = getEntity(args);
        //尝试通过service.getEntity()查找entity
        if (entity == null) {
            Method entityMethod = ReflectUtil.getMethodByName(service.getClass(), "getEntity");
            if (entityMethod != null) {
                Object result = ReflectUtil.invoke(service, entityMethod, null);
                if (result != null && result instanceof IEntity)
                    return (IEntity) result;
            }
        }
        if (entity == null)
            throw new RuntimeException(String.format("未找到服务对象[%1$s]对应的实体信息", service.getClass().getSimpleName()));

        return entity;
    }

    /**
     * 判断当前行为是否为内置行为
     *
     * @param service
     * @param action
     * @param args
     * @return
     */
    protected boolean enableMethod(Object service, String action, Object[] args) {
        if ("createBatch".equalsIgnoreCase(action)
                || "updateBatch".equalsIgnoreCase(action)
                || "saveBatch".equalsIgnoreCase(action)
                || "removeBatch".equalsIgnoreCase(action)
                || "checkKey".equalsIgnoreCase(action)
                || (action.startsWith("removeBy") && !ObjectUtils.isEmpty(args))
                || (action.startsWith("saveBy") && !ObjectUtils.isEmpty(args) && args.length == 2)
                || (action.startsWith("findBy") && !ObjectUtils.isEmpty(args))
                || (getEntity(args) == null)
        )
            return false;
        else
            return true;
    }

    /**
     * 是否为自定义行为
     * @param iPSDEAction
     * @return
     */
    protected boolean isCustomAction(IDataEntityRuntime dataEntityRuntime, IPSDEAction iPSDEAction) {
        return DEActionTypes.USERCUSTOM.equals(iPSDEAction.getActionType()) || DEActionTypes.SELECTBYKEY.equals(iPSDEAction.getActionType())
                || (DATAENTITY_STORAGEMODE_NONE == dataEntityRuntime.getStorageMode() && dataEntityRuntime.isVirtual() && DATAENTITY_VIRTUALMODE_INDEXMAJOR == dataEntityRuntime.getVirtualMode());
    }

    /**
     * 额外参数处理，取消前端传入的联合主键
     * @param args
     */
    protected void processArgs(Object[] args) {
        if(args == null)
            return ;

        for(Object arg : args){
            if (arg instanceof IEntity) {
                processArg((IEntity) arg);
            } else if (arg instanceof List) {
                for (Object obj : (List) arg) {
                    if(obj instanceof IEntity)
                        processArg((IEntity) obj);
                }
            }
        }
    }

    /**
     * 额外参数处理，取消前端传入的联合主键
     * @param entity
     */
    protected void processArg(IEntity entity){
        if(entity == null)
            return;

        Set<String> fields = BeanCache.get(entity.getClass()).getFieldMap().keySet();
        for(String field: fields){
            if(!ObjectUtils.isEmpty(entity.get(field)) && entity.get(field).toString().startsWith("__empty__"))
                entity.reset(field);
        }
    }
}
